package com.am.server.api.system.user.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.DES;
import com.am.server.api.system.permission.config.model.Menu;
import com.am.server.api.system.permission.dao.cache.MenuCacheDao;
import com.am.server.api.system.permission.service.UserPermissionCacheService;
import com.am.server.api.system.role.model.entity.RoleEntity;
import com.am.server.api.system.user.dao.rdb.AdminUserDao;
import com.am.server.api.system.user.exception.NoPermissionAccessException;
import com.am.server.api.system.user.exception.PasswordErrorException;
import com.am.server.api.system.user.exception.UserNotExistException;
import com.am.server.api.system.user.model.dto.LoginDto;
import com.am.server.api.system.user.model.dto.LoginUserInfoDto;
import com.am.server.api.system.user.model.dto.UpdateLoginUserInfoDto;
import com.am.server.api.system.user.model.dto.UserInfoDto;
import com.am.server.api.system.user.model.entity.AdminUserEntity;
import com.am.server.api.system.user.service.LoginUserService;
import com.am.server.common.annotation.transaction.ReadOnly;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

/**
 * @author 阮雪峰
 */
@Slf4j
@Service
public class LoginUserServiceImpl implements LoginUserService {

    private final AdminUserDao adminUserDao;
    private final UserPermissionCacheService userPermissionCacheService;
    private final MenuCacheDao menuCacheDao;

    public LoginUserServiceImpl(AdminUserDao adminUserDao, UserPermissionCacheService userPermissionCacheService, MenuCacheDao menuCacheDao) {
        this.adminUserDao = adminUserDao;
        this.userPermissionCacheService = userPermissionCacheService;
        this.menuCacheDao = menuCacheDao;
    }

    @ReadOnly
    @Override
    public LoginUserInfoDto login(LoginDto dto) {
        Optional<AdminUserEntity> optional = adminUserDao.findByUsername(dto.getUsername());
        if (optional.isEmpty()) {
            throw new UserNotExistException();
        }

        return optional.filter(user -> {
                    //校验密码是否一样
                    DES des = SecureUtil.des(Base64.decode(user.getSalt()));
                    String userPassword = des.decryptStr(user.getPassword());
                    return CharSequenceUtil.equals(new String(Base64.decode(dto.getPassword())), userPassword);
                })
                .map(user -> {
                    List<Menu> permissions = userPermissionCacheService.saveOrGet(user.getId());
                    if (permissions != null && !permissions.isEmpty()) {
                        StpUtil.login(user.getId(), Boolean.TRUE.equals(dto.getRememberMe()));
                        return new LoginUserInfoDto(StpUtil.getTokenValue());
                    } else {
                        throw new NoPermissionAccessException();
                    }

                })
                .orElseThrow(PasswordErrorException::new);
    }

    @ReadOnly
    @Override
    public UserInfoDto info(Long id) {
        return adminUserDao.findById(id)
                .map(user -> {
                    List<String> roles = user.getRoles().stream().map(RoleEntity::getName).toList();
                    String avatar = user.getAvatar() == null ? "" : user.getAvatar();
                    String homePath = menuCacheDao.findById(user.getHomePageId()).map(Menu::getFullPath).orElse(null);
                    return new UserInfoDto()
                            .setId(user.getId())
                            .setUsername(user.getUsername())
                            .setAvatar(avatar)
                            .setEmail(user.getEmail())
                            .setGender(user.getGender())
                            .setRoles(roles)
                            .setHomePath(homePath);
                })
                .orElseThrow(UserNotExistException::new);
    }

    @Override
    public void update(UpdateLoginUserInfoDto user) {
        adminUserDao.findById(user.getId())
                .ifPresent(adminUser -> {
                    adminUser.setEmail(user.getEmail());
                    adminUser.setGender(user.getGender());
                    adminUser.setAvatar(user.getAvatar());
                    adminUserDao.save(adminUser);
                });
    }

    @Override
    public List<Menu> getMenuList() {
        return userPermissionCacheService.saveOrGet(StpUtil.getLoginIdAsLong());
    }

    @Override
    public void logout() {
        StpUtil.logout();
    }

    @Override
    public void refreshUserPermission(Long uid) {
        userPermissionCacheService.refresh(uid);
    }
}
